<?php
namespace WeChat;
use Swiftx\Base\Object;
use Swiftx\Internet\Curl;

/**
 * ---------------------------------------------------------------------------------------------------------------------
 * AccessToken
 * ---------------------------------------------------------------------------------------------------------------------
 * @author		胡永强  <odaytudio@gmail.com>
 * @since		2015-12-15
 * @copyright	Copyright (c) 2014-2015 Swiftx Inc.
 * ---------------------------------------------------------------------------------------------------------------------
 * @property-read string $Src       脚本引入地址
 * @property-read string $AppId     公众号的唯一标识
 * @property-read string $TimeStamp 生成签名的时间戳
 * @property-read string $NonceStr  生成签名的随机串
 * @property-read string $Signature 签名
 * @property-read array  $JsApiList 需要使用的JS接口列表
 * ---------------------------------------------------------------------------------------------------------------------
 */
class Api extends Object {

    const TokenUri = 'https://api.weixin.qq.com/cgi-bin/token';
    const CallBackIPUri = 'https://api.weixin.qq.com/cgi-bin/getcallbackip';
    const TicketUri = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket';
    const OAuthUri = 'https://api.weixin.qq.com/sns/oauth2/access_token';
    const OAuthPage = 'https://open.weixin.qq.com/connect/oauth2/authorize';
    const UserInfoUri = 'https://api.weixin.qq.com/sns/userinfo';
    const JsSdkHttpSrc = 'http://res.wx.qq.com/open/js/jweixin-1.0.0.js';
    const JsSdkHttpsSrc = 'http://res.wx.qq.com/open/js/jweixin-1.0.0.js';

    /**
     * 获取AccessToken
     * @param string $appid
     * @param string $secret
     * @return Token
     * @throws Exception
     */
    public static function FetchAccessToken($appid, $secret){
        $option['grant_type'] = 'client_credential';
        $option['appid'] = $appid;
        $option['secret'] = $secret;
        $result = Curl::SendJsonGet(static::TokenUri,$option);
        if(isset($result['access_token']))
            return new Token($result['access_token'],$result['expires_in']);
        throw new Exception($result['errmsg'], $result['errcode']);
    }

    /**
     * 获取微信服务器IP
     * @param string $token
     * @return array
     * @throws Exception
     */
    public static function FetchCallBackIP($token){
        $option['access_token'] = $token;
        $result = Curl::SendJsonGet(static::CallBackIPUri,$option);
        if(isset($result['ip_list'])) return $result['ip_list'];
        throw new Exception($result['errmsg'], $result['errcode']);
    }

    /**
     * 获取JsApiTicket
     * @param string $token
     * @return Ticket
     * @throws Exception
     */
    public static function FetchJsApiTicket($token){
        $option['access_token'] = $token;
        $option['type'] = 'jsapi';
        $result = Curl::SendJsonGet(static::TicketUri,$option);
        if($result['errcode'] == 0)
            return new Ticket($result['ticket'],$result['expires_in']);
        throw new Exception($result['errmsg'], $result['errcode']);
    }

    /**
     * 签名生成算法
     * @param string $key
     * @param string $ticket
     * @param int $time
     * @param string $url
     * @return string
     */
    public static function CalculateSignature($key, $ticket,$time, $url){
        $str = 'jsapi_ticket='.$ticket.'&noncestr='.$key.'&timestamp='.$time.'&url='.$url;
        return sha1($str);
    }

    /**
     * 获取授权页面的URL
     * @param string $uri
     * @param string $appid
     * @param string $method
     * @param int $state
     * @return string
     * @throws Exception
     */
    protected static function OAuthUri($uri, $appid, $method='snsapi_userinfo', $state=1){
        if(!in_array($method, ['snsapi_userinfo', 'snsapi_base']))
            throw new Exception('参数不正确', 500);
        $url = static::OAuthPage.'?appid='.$appid.'&redirect_uri='.$uri;
        return $url.'&response_type=code&scope='.$method.'&state='.$state.'#wechat_redirect';
    }

    /**
     * 获取微信token
     * @param string $code
     * @param string $appid
     * @param string $secret
     * @return mixed
     * @throws Exception
     */
    protected static function FetchOAuth($code, $appid, $secret){
        $option['appid'] = $appid;
        $option['secret'] = $secret;
        $option['code'] = $code;
        $option['grant_type'] = 'authorization_code';
        $result = Curl::SendJsonGet(static::OAuthUri, $option);
        if(isset($result['openid']))
            return new OAuth($result['open_id'], $result['expires_in'], $result['access_token'], $result['refresh_token'], explode(',',$result['scope']));
        throw new Exception($result['errmsg'], $result['errcode']);
    }

    /**
     * 获取微信用户信息
     * @param string $open_id
     * @param string $access_token
     * @return User
     * @throws Exception
     */
    protected static function FetchUser($open_id, $access_token){
        $option['access_token'] = $access_token;
        $option['openid'] = $open_id;
        $result = Curl::SendJsonGet(static::UserInfoUri, $option);
        if(isset($result['openid'])) {
            if($result['sex'] == 1) $result['sex'] = true;
            else if($result['sex'] == 2) $result['sex'] = false;
            else $result['sex'] = null;
            $result['headimgurl'] = substr($result['headimgurl'], 0, -1);
            return new User(
                $result['openid'], $result['nickname'], $result['sex'], $result['language'], $result['city'],
                $result['province'], $result['country'], $result['headimgurl'], $result['privilege']
            );
        }
        throw new Exception($result['errmsg'], $result['errcode']);
    }

}